#!/usr/bin/env python
# -*- coding: utf-8 -*-

'''
@File    : http_client.py
@Description : HTTP请求模块，封装requests库，提供HTTP请求功能
'''

import json
import requests
from typing import Dict, Any, Optional, Union, List, Tuple
import allure

# 导入配置和日志
from config.settings import config
from utils.log_handler import get_logger


class HttpClient:
    """
    HTTP客户端类，封装requests库，提供HTTP请求功能
    """
    def __init__(self, base_url: str = None):
        """
        初始化HTTP客户端
        
        Args:
            base_url: 基础URL，默认为None，使用配置文件中的基础URL
        """
        self.base_url = base_url or config.base_url
        self.session = requests.Session()
        self.logger = get_logger("http_client")
    
    def _log_request(self, method: str, url: str, **kwargs) -> None:
        """
        记录请求日志
        
        Args:
            method: 请求方法
            url: 请求URL
            **kwargs: 请求参数
        """
        self.logger.info(f"Request: {method} {url}")
        if kwargs.get('headers'):
            self.logger.debug(f"Headers: {kwargs.get('headers')}")
        if kwargs.get('params'):
            self.logger.debug(f"Params: {kwargs.get('params')}")
        if kwargs.get('data'):
            self.logger.debug(f"Data: {kwargs.get('data')}")
        if kwargs.get('json'):
            self.logger.debug(f"JSON: {kwargs.get('json')}")
    
    def _log_response(self, response: requests.Response) -> None:
        """
        记录响应日志
        
        Args:
            response: 响应对象
        """
        self.logger.info(f"Response: {response.status_code} {response.reason}")
        self.logger.debug(f"Response Headers: {response.headers}")
        try:
            self.logger.debug(f"Response Body: {response.json()}")
        except ValueError:
            self.logger.debug(f"Response Body: {response.text}")
    
    def _allure_record(self, method: str, url: str, response: requests.Response, **kwargs) -> None:
        """
        记录请求和响应信息到Allure报告
        
        Args:
            method: 请求方法
            url: 请求URL
            response: 响应对象
            **kwargs: 请求参数
        """
        with allure.step(f"{method} {url}"):
            # 记录请求信息
            allure.attach(url, "Request URL", allure.attachment_type.TEXT)
            allure.attach(method, "Request Method", allure.attachment_type.TEXT)
            
            # 记录请求头
            if kwargs.get('headers'):
                allure.attach(json.dumps(kwargs.get('headers'), indent=2, ensure_ascii=False), 
                             "Request Headers", allure.attachment_type.JSON)
            
            # 记录请求参数
            if kwargs.get('params'):
                allure.attach(json.dumps(kwargs.get('params'), indent=2, ensure_ascii=False), 
                             "Request Params", allure.attachment_type.JSON)
            
            # 记录请求体
            if kwargs.get('data'):
                if isinstance(kwargs.get('data'), dict):
                    allure.attach(json.dumps(kwargs.get('data'), indent=2, ensure_ascii=False), 
                                 "Request Data", allure.attachment_type.JSON)
                else:
                    allure.attach(str(kwargs.get('data')), "Request Data", allure.attachment_type.TEXT)
            
            if kwargs.get('json'):
                allure.attach(json.dumps(kwargs.get('json'), indent=2, ensure_ascii=False), 
                             "Request JSON", allure.attachment_type.JSON)
            
            # 记录响应信息
            allure.attach(str(response.status_code), "Response Status Code", allure.attachment_type.TEXT)
            allure.attach(json.dumps(dict(response.headers), indent=2, ensure_ascii=False), 
                         "Response Headers", allure.attachment_type.JSON)
            
            # 记录响应体
            try:
                allure.attach(json.dumps(response.json(), indent=2, ensure_ascii=False), 
                             "Response Body", allure.attachment_type.JSON)
            except ValueError:
                allure.attach(response.text, "Response Body", allure.attachment_type.TEXT)
    
    def request(self, method: str, url: str, **kwargs) -> requests.Response:
        """
        发送HTTP请求
        
        Args:
            method: 请求方法
            url: 请求URL
            **kwargs: 请求参数
            
        Returns:
            响应对象
        """
        # 如果URL不是以http开头，则拼接基础URL
        if not url.startswith(('http://', 'https://')):
            url = f"{self.base_url.rstrip('/')}/{url.lstrip('/')}" 
        
        # 记录请求日志
        self._log_request(method, url, **kwargs)
        
        # 发送请求
        response = self.session.request(method, url, **kwargs)
        
        # 记录响应日志
        self._log_response(response)
        
        # 记录到Allure报告
        self._allure_record(method, url, response, **kwargs)
        
        return response
    
    def get(self, url: str, params: Dict[str, Any] = None, **kwargs) -> requests.Response:
        """
        发送GET请求
        
        Args:
            url: 请求URL
            params: 查询参数
            **kwargs: 其他请求参数
            
        Returns:
            响应对象
        """
        return self.request('GET', url, params=params, **kwargs)
    
    def post(self, url: str, data: Any = None, json: Dict[str, Any] = None, **kwargs) -> requests.Response:
        """
        发送POST请求
        
        Args:
            url: 请求URL
            data: 请求数据
            json: JSON请求数据
            **kwargs: 其他请求参数
            
        Returns:
            响应对象
        """
        return self.request('POST', url, data=data, json=json, **kwargs)
    
    def put(self, url: str, data: Any = None, **kwargs) -> requests.Response:
        """
        发送PUT请求
        
        Args:
            url: 请求URL
            data: 请求数据
            **kwargs: 其他请求参数
            
        Returns:
            响应对象
        """
        return self.request('PUT', url, data=data, **kwargs)
    
    def delete(self, url: str, **kwargs) -> requests.Response:
        """
        发送DELETE请求
        
        Args:
            url: 请求URL
            **kwargs: 其他请求参数
            
        Returns:
            响应对象
        """
        return self.request('DELETE', url, **kwargs)
    
    def patch(self, url: str, data: Any = None, **kwargs) -> requests.Response:
        """
        发送PATCH请求
        
        Args:
            url: 请求URL
            data: 请求数据
            **kwargs: 其他请求参数
            
        Returns:
            响应对象
        """
        return self.request('PATCH', url, data=data, **kwargs)
    
    def head(self, url: str, **kwargs) -> requests.Response:
        """
        发送HEAD请求
        
        Args:
            url: 请求URL
            **kwargs: 其他请求参数
            
        Returns:
            响应对象
        """
        return self.request('HEAD', url, **kwargs)
    
    def options(self, url: str, **kwargs) -> requests.Response:
        """
        发送OPTIONS请求
        
        Args:
            url: 请求URL
            **kwargs: 其他请求参数
            
        Returns:
            响应对象
        """
        return self.request('OPTIONS', url, **kwargs)
    
    def close(self) -> None:
        """
        关闭会话
        """
        self.session.close()
    
    def __enter__(self):
        """
        支持with语句
        
        Returns:
            HTTP客户端对象
        """
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """
        退出with语句时关闭会话
        
        Args:
            exc_type: 异常类型
            exc_val: 异常值
            exc_tb: 异常回溯
        """
        self.close()


if __name__ == '__main__':
    # 测试HTTP客户端
    client = HttpClient()
    response = client.get('https://httpbin.org/get')
    print(response.status_code)
    print(response.json())